﻿using System.Diagnostics;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using Converter = System.Convert;

namespace Lib.Security;

/// <summary>
/// 加密解密(MD5、SHA、DES）
/// </summary>
public static class Password {
    /// <summary>
    /// 
    /// </summary>
    private static string CPUKey;
    /// <summary>
    /// 获取 CPUID
    /// </summary>
    public static string CPUID {
        get {
            try {
                if (string.IsNullOrEmpty(CPUKey)) {
                    if (OperatingSystem.IsWindows()) {
                        using var Searcher = new ManagementObjectSearcher("SELECT ProcessorId FROM Win32_Processor");
                        foreach (var obj in Searcher.Get()) {
                            return CPUKey = obj["ProcessorId"]?.ToString() ?? default;
                        }
                    }
                    if (OperatingSystem.IsLinux()) {
                        var _Process = new Process();
                        _Process.StartInfo.FileName = "/bin/bash";
                        _Process.StartInfo.Arguments = "-c \"dmidecode -t processor | grep 'ID' | head -1\"";
                        _Process.StartInfo.UseShellExecute = false;
                        _Process.StartInfo.RedirectStandardOutput = true;
                        _Process.Start();
                        var _OutPut = _Process.StandardOutput.ReadToEnd();
                        _Process.WaitForExit();
                        return CPUKey = _OutPut.Trim().GetHashCode().ToString("X");
                    }
                    if (OperatingSystem.IsMacOS()) {
                        var _Process = new Process();
                        _Process.StartInfo.FileName = "/bin/bash";
                        _Process.StartInfo.Arguments = "-c \"ioreg -l | grep 'IOPlatformSerialNumber'\"";
                        _Process.StartInfo.UseShellExecute = false;
                        _Process.StartInfo.RedirectStandardOutput = true;
                        _Process.Start();
                        var _OutPut = _Process.StandardOutput.ReadToEnd();
                        _Process.WaitForExit();
                        return CPUKey = _OutPut.Trim().GetHashCode().ToString("X");
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine($"获取失败: {ex.Message}");
            }
            return CPUKey;
        }
    }

    /// <summary>
    /// MD5（32位）方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string MD5(this string Source, bool isBASE64 = false) {
        return SHA(Source, AlgorithType.MD5, isBASE64);
    }
    /// <summary>
    /// SHA1 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string SHA1(this string Source, bool isBASE64 = false) {
        return SHA(Source, AlgorithType.SHA1, isBASE64);
    }
    /// <summary>
    /// SHA256 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string SHA256(this string Source, bool isBASE64 = false) {
        return SHA(Source, AlgorithType.SHA256, isBASE64);
    }

    /// <summary>
    /// SHA384 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string SHA384(this string Source, bool isBASE64 = false) {
        return SHA(Source, AlgorithType.SHA384, isBASE64);
    }
    /// <summary>
    /// SHA512 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string SHA512(this string Source, bool isBASE64 = false) {
        return SHA(Source, AlgorithType.SHA512, isBASE64);
    }


    /// <summary>
    /// HMACMD5 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string HMACMD5(this string Source, string Key, bool isBASE64 = false) {
        return HMACSHA(Source, Key, AlgorithType.HMACMD5, isBASE64);
    }
    /// <summary>
    /// HMACSHA1 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string HMACSHA1(this string Source, string Key, bool isBASE64 = false) {
        return HMACSHA(Source, Key, AlgorithType.HMACSHA1, isBASE64);
    }
    /// <summary>
    /// HMACSHA256 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="isBASE64">是否返回 BASE64 编码类型加密字符串</param>
    /// <returns></returns>
    public static string HMACSHA256(this string Source, string Key, bool isBASE64 = false) {
        return HMACSHA(Source, Key, AlgorithType.HMACSHA256, isBASE64);
    }
    /// <summary>
    /// HMACSHA384 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string HMACSHA384(this string Source, string Key, bool isBASE64 = false) {
        return HMACSHA(Source, Key, AlgorithType.HMACSHA384, isBASE64);
    }
    /// <summary>
    /// HMACSHA512 方式加密, 失败返回 NULL, 成功返回字符串（isBASE64 = False, 返回十六进制字符串; isBASE64 = True, 返回 BASE64 数字编码等效字符串）
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    public static string HMACSHA512(this string Source, string Key, bool isBASE64 = false) {
        return HMACSHA(Source, Key, AlgorithType.HMACSHA512, isBASE64);
    }

    /// <summary>
    /// MD5、SHA1、SHA256、SHA384、SHA512 方式加密，, 失败返回 NULL, 成功返回字节数组
    /// </summary>
    /// <param name="Source">要加密字节数组</param>
    /// <param name="Code">加密类型编码：MD5、SHA1、SHA256、SHA384、SHA512</param>
    /// <returns>返回字节数组</returns>
    public static byte[] SHA(byte[] Source, AlgorithType Code) {
        if (Source == null) {
            return null;
        }
        var Key = Code.ToString();
        switch (Key) {
            case "MD5":
                return System.Security.Cryptography.MD5.HashData(Source);
            case "SHA1":
                return System.Security.Cryptography.SHA1.HashData(Source);
            case "SHA256":
                return System.Security.Cryptography.SHA256.HashData(Source);
            case "SHA384":
                return System.Security.Cryptography.SHA384.HashData(Source);
            case "SHA512":
                return System.Security.Cryptography.SHA512.HashData(Source);
            default:
                break;
        }
        return null;
    }
    /// <summary>
    /// MD5、SHA1、SHA256、SHA384、SHA512 方式加密，, 失败返回 NULL, 成功返回字符串
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Code">加密类型编码：MD5、SHA1、SHA256、SHA384、SHA512</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    private static string SHA(string Source, AlgorithType Code, bool isBASE64) {
        if (string.IsNullOrEmpty(Source)) {
            return null;
        }
        byte[] Bytes = SHA(Encoding.UTF8.GetBytes(Source),Code);
        if (Bytes == null) {
            return null;
        }
        if (isBASE64) {
            return Converter.ToBase64String(Bytes);
        } else {
            return Convert.ToHexString(Bytes).ToUpper();
        }
    }
    /// <summary>
    /// HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512 方式加密，失败返回 NULL，成功返回字节数组
    /// </summary>
    /// <param name="Source">要加密字节数组</param>
    /// <param name="Key">加密密钥（字节数组）</param>
    /// <param name="Code">加密类型编码：HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512</param>
    /// <returns>返回字节数组</returns>
    public static byte[] HMACSHA(byte[] Source, byte[] Key, AlgorithType Code) {
        if (Source == null || Key == null) {
            return null;
        }
        var CodeKey = Code.ToString();
        switch (CodeKey) {
            case "HMACMD5":
                return System.Security.Cryptography.HMACMD5.HashData(Key, Source);
            case "HMACSHA1":
                return System.Security.Cryptography.HMACSHA1.HashData(Key, Source);
            case "HMACSHA256":
                return System.Security.Cryptography.HMACSHA256.HashData(Key, Source);
            case "HMACSHA384":
                return System.Security.Cryptography.HMACSHA384.HashData(Key, Source);
            case "HMACSHA512":
                return System.Security.Cryptography.HMACSHA512.HashData(Key, Source);
            default:
                break;
        }
        return null;
    }
    /// <summary>
    /// HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512 方式加密，失败返回 NULL，成功返回字符串
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    /// <param name="Code">加密类型编码：HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512</param>
    /// <param name="isBASE64">isBASE64 = False, 返回十六进制字符串; isBASE64 = True 返回 BASE64 编码字符串</param>
    /// <returns>已加密字符串</returns>
    private static string HMACSHA(string Source, string Key, AlgorithType Code, bool isBASE64) {
        if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Key)) {
            return null;
        }
        byte[] Bytes = HMACSHA(Encoding.UTF8.GetBytes(Source), Encoding.UTF8.GetBytes(Key), Code);
        if (Bytes == null) {
            return null;
        }
        if (isBASE64) {
            return Converter.ToBase64String(Bytes);
        } else {
            return Convert.ToHexString(Bytes).ToUpper();
        }
    }
    /// <summary>
    /// DES 方式加密，失败返 NULL
    /// </summary>
    /// <param name="Source">要加密字符串</param>
    /// <param name="Key">加密密钥</param>
    public static string Encrypt(this string Source, string Key) {
        try {
            if (string.IsNullOrEmpty(Key) || string.IsNullOrEmpty(Source)) {
                return null;
            }
            byte[] Byte = Encoding.UTF8.GetBytes(Source);
            var DES = System.Security.Cryptography.DES.Create();
            if (Key.Length != 8) {
                Key = MD5(Key);
                DES.Key = Encoding.UTF8.GetBytes(Key[..8]);
                DES.IV = Encoding.UTF8.GetBytes(Key.Substring(8, 8));
            } else {
                DES.Key = Encoding.UTF8.GetBytes(Key);
                DES.IV = Encoding.UTF8.GetBytes(MD5(Key).Substring(8, 8));
            }
            using var MS = new MemoryStream();
            using (var Stream = new CryptoStream(MS, DES.CreateEncryptor(), CryptoStreamMode.Write)) {
                Stream.Write(Byte, 0, Byte.Length);
                Stream.FlushFinalBlock();
            }
            return Converter.ToBase64String(MS.ToArray());
        } catch {
            return null;
        }
    }
    /// <summary>
    /// DES 方式解密，失败返 NULL
    /// </summary>
    /// <param name="Source">要解密字符串</param>
    /// <param name="Key">解密密钥</param>
    public static string Decrypt(this string Source, string Key) {
        try {
            if (string.IsNullOrEmpty(Key) || string.IsNullOrEmpty(Source)) {
                return null;
            }
            var Byte = Converter.FromBase64String(Source);
            var DES = System.Security.Cryptography.DES.Create();
            if (Key.Length != 8) {
                Key = MD5(Key);
                DES.Key = Encoding.UTF8.GetBytes(Key[..8]);
                DES.IV = Encoding.UTF8.GetBytes(Key.Substring(8, 8));
            } else {
                DES.Key = Encoding.UTF8.GetBytes(Key);
                DES.IV = Encoding.UTF8.GetBytes(MD5(Key).Substring(8, 8));
            }
            using var MS = new MemoryStream();
            using (var Stream = new CryptoStream(MS, DES.CreateDecryptor(), CryptoStreamMode.Write)) {
                Stream.Write(Byte, 0, Byte.Length);
                Stream.FlushFinalBlock();
            }
            return Encoding.UTF8.GetString(MS.ToArray());
        } catch {
            return null;
        }
    }

}

